import java.util.ArrayList;
import java.util.Arrays;

public class PlayerNBoxes implements Comparable<PlayerNBoxes>{
	
	protected Position player;
	protected Position[] boxes;
	
	protected int rank=0;
	
	
	public PlayerNBoxes(int lNumRows, int lNumColumns, ArrayList<String> input){
		ArrayList<Position> boxes = new ArrayList<Position>();
        for (int i=0;i<lNumRows;i++){
        	for (int j=0;j<lNumColumns;j++){
        		char ij = input.get(i).charAt(j);
        	    if (ij == '$'){
        			boxes.add(new Position(i,j));
        	    }else if (ij == '*'){
          			boxes.add(new Position(i,j));
        		} else if (ij == '@'){
        			player = new Position(i,j);
        		} 
        		else if (ij == '+'){
        			player = new Position(i,j);
        		} 
        	}
        }
		this.boxes = new Position[boxes.size()];
		for ( int i = 0; i < boxes.size(); i++){
			this.boxes[i] = boxes.get(i);
		}
	}
	
	public PlayerNBoxes(Position initalPlayerPos, ArrayList<Position> inputBoxes) {
		player = initalPlayerPos;
		boxes = new Position[inputBoxes.size()];
		for ( int i = 0; i < inputBoxes.size(); i++){
			boxes[i] = inputBoxes.get(i);
		}
	}

	public PlayerNBoxes(Position initalPlayerPos, Position[] inputBoxes) {
		player = initalPlayerPos;
		boxes = inputBoxes; 
	}
	
	public PlayerNBoxes(PlayerNBoxes pnb){
		player = pnb.getPlayer();
		boxes = new Position[pnb.getBoxesSize()];
		for ( int i = 0; i < pnb.getBoxesSize(); i++){
			this.boxes[i] = pnb.getBoxes()[i];
		}
		java.util.Arrays.sort( boxes);
	}
	
	public String toString(){
		String re = "player: "+player +"; ";
		re += "boxes: ";
		for ( Position p : boxes){
			re+= p+" , ";
		}
		return re;
	}
	
	public byte[][] toByteArray(int xDim, int yDim){
		byte[][] re = new byte[xDim][yDim];
		for ( int x = 0; x < xDim; x++){
			for (int y = 0; y < yDim; y++ ){
				re[x][y] = 0;
			}
		}
		for ( Position pos : boxes){
			re [pos.getI()][pos.getJ()] = 2;
		}
		re [player.getI()][player.getJ()] = 100;
		return re;
	}
	
	public Position getPlayer() {
		return player;
	}

	public void setPlayer(Position player) {
		this.player = player;
	}

	public Position[] getBoxes() {
		Position[] re = new Position[boxes.length];
		for ( int i = 0; i < boxes.length; i++){
			Position tmp = new Position(boxes[i]);
			re[i] = tmp;
		}
		return re;
	}

	public int getBoxesSize(){
		return boxes.length;
	}
	
	public void setBoxes(Position[] boxes) {
		this.boxes = boxes;
		java.util.Arrays.sort( boxes);
	}
	
	public void setBoxes(ArrayList<Position> inputBoxes){
		boxes = new Position[inputBoxes.size()];
		for ( int i = 0; i < inputBoxes.size(); i++){
			boxes[i] = inputBoxes.get(i);
		}
		java.util.Arrays.sort( boxes);
	}
	
	public Position getBoxAt(int i, int j){
		for ( Position pos : boxes){
			if ( pos.getI() == i && pos.getJ() == j){
				return pos;
			}
		}
		return null;
	}
	
	public void moveBox(Position start, Position end){
		for (int i=0; i< boxes.length; i++){
			if ( boxes[i].isEqual(start)){
				boxes[i] = end;
			}
		}
		java.util.Arrays.sort( boxes);
	}
	
	public PlayerNBoxes move(Move m) throws CloneNotSupportedException{
		PlayerNBoxes pnb = (PlayerNBoxes) this.clone();
		for (int i=0; i<pnb.boxes.length; i++){
			if (pnb.boxes[i].isEqual(m.getStart())){
//				System.out.println("moving boxes");
				pnb.boxes[i] = m.getEnd();
			}
		}
		pnb.player = new Position(m.getStart());
//		System.out.println("player pos "+pnb.player);
		return pnb;
	}
	
	public PlayerNBoxes clone(){
		ArrayList<Position> boxes = new ArrayList<Position>();
		for (int i=0; i<this.boxes.length; i++) boxes.add(this.boxes[i]);
		PlayerNBoxes pnb = new PlayerNBoxes(this.player, boxes);
		return pnb;
	}
	
	public boolean contains (int i, int j){
		boolean ans = false;
		for (int k=0;k<this.boxes.length;k++)
			if (this.boxes[k].getI()==i && this.boxes[k].getJ()==j) ans=true;
		return ans;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		for ( int i = 0; i < boxes.length; i++){
			result = prime * result + boxes[i].hashCode();
		}
//		result = prime * result + Arrays.hashCode(boxes);
		result = prime * result + ((player == null) ? 0 : player.hashCode());
		return result;
	}

//	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		PlayerNBoxes other = (PlayerNBoxes) obj;
		if (!Arrays.equals(boxes, other.boxes))// && playerInArea()==other.playerInArea())
			return false;
//		if (player == null) {
//			if (other.player != null)
//				return false;
		
		if (!player.equals(other.player))
			return false;
		return true;
		
//		PlayerNBoxes other = (PlayerNBoxes) obj;
//		if ( !player.equals(other.player)){
//			return false;
//		}
//		for( Position p: boxes){
//			if ( other.getBoxAt(p.getI(), p.getJ()) == null){
//
//				return false;
//			}
//		}
//		return true;
	}
	
	// Move the player on the board
	// useful for debugging a wrong solution when found
	
//	public int playerInArea(){
//		
//		// building the array for comparision;
//		
//		int count=0;
//		
//		for(int r=0;r<10;r++)
//		{
//			for(int c=0;c<10;c++)
//			{
//				
//			}
//		}
//		
//		
//		return 1;
//	}
	public void movePlayer(char c) throws CloneNotSupportedException{
		if (c=='U'){
			this.player.setI(this.player.getI()-1);
			if (this.contains(this.player.getI(), this.player.getJ())){
				Move m = new Move(new Position(this.player.getI(), this.player.getJ()),Move.MOVE_UP);
				this.moveBox(m.getStart(), m.getEnd());
			}
		}
		else if (c=='D'){
			this.player.setI(this.player.getI()+1);
			if (this.contains(this.player.getI(), this.player.getJ())){
				Move m = new Move(new Position(this.player.getI(), this.player.getJ()),Move.MOVE_DOWN);
				this.moveBox(m.getStart(), m.getEnd());
			}		
		}
		else if (c=='L'){
			this.player.setJ(this.player.getJ()-1);
			if (this.contains(this.player.getI(), this.player.getJ())){
				Move m = new Move(new Position(this.player.getI(), this.player.getJ()),Move.MOVE_LEFT);
				this.moveBox(m.getStart(), m.getEnd());
			}				
		}
		else if (c=='R'){
			this.player.setJ(this.player.getJ()+1);
			if (this.contains(this.player.getI(), this.player.getJ())){
				Move m = new Move(new Position(this.player.getI(), this.player.getJ()),Move.MOVE_RIGHT);
				this.moveBox(m.getStart(), m.getEnd());
			}				
		}
		else System.out.println("Problem "+c);
	}
	
	public void setRank(int[][] array) {
		int ans = 0;
		for (Position  p : this.boxes){
			ans += array[p.getI()][p.getJ()];
		}
		this.rank = ans;
	}

	public int getRank() {
		return rank;
	}

	@Override
	public int compareTo(PlayerNBoxes o) {
		for (int i = 0; i < boxes.length; i++ ){
			if ( boxes[i].compareTo(o.getBoxes()[i]) > 0){
				return 1;
			}
			if ( boxes[i].compareTo(o.getBoxes()[i]) < 0){
				return -1;
			}
		}
		
		if ( State.getPAreaID( this) == State.getPAreaID( o)){
			return 0;
		}
		
		return player.compareTo(o.player);
	}
	
}
